1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 import java.text.*;
31 import java.util.*;
32
33 public class ISO8601ZoneTest {
34 static final Date TIMESTAMP = new Date(1283758039020L);
35
36 static final String[][] formatData = {
37
38 { "America/Los_Angeles", "2010-09-06T00:27:19.020-07", },
39 { "America/Los_Angeles", "2010-09-06T00:27:19.020-0700", },
40 { "America/Los_Angeles", "2010-09-06T00:27:19.020-07:00", },
41 { "Australia/Sydney", "2010-09-06T17:27:19.020+10", },
42 { "Australia/Sydney", "2010-09-06T17:27:19.020+1000", },
43 { "Australia/Sydney", "2010-09-06T17:27:19.020+10:00", },
44 { "GMT-07:00", "2010-09-06T00:27:19.020-07", },
45 { "GMT-07:00", "2010-09-06T00:27:19.020-0700", },
46 { "GMT-07:00", "2010-09-06T00:27:19.020-07:00", },
47 { "UTC", "2010-09-06T07:27:19.020Z", },
48 { "UTC", "2010-09-06T07:27:19.020Z", },
49 { "UTC", "2010-09-06T07:27:19.020Z", },
50 };
51
52 static final String[] zones = {
53 "America/Los_Angeles", "Australia/Sydney", "GMT-07:00",
54 "UTC", "GMT+05:30", "GMT-01:23",
55 };
56
57 static final String[] isoZoneFormats = {
58 "yyyy-MM-dd'T'HH:mm:ss.SSSX",
59 "yyyy-MM-dd'T'HH:mm:ss.SSSXX",
60 "yyyy-MM-dd'T'HH:mm:ss.SSSXXX",
61 };
62
63
64
65
66 static final String[][] badData = {
67 { "X", "1", "1" },
68 { "X", "+1", "+1" },
69 { "X", "-2", "-2" },
70 { "X", "-24", "-2" },
71 { "X", "+24", "+2" },
72
73 { "XX", "9", "9" },
74 { "XX", "23", "2" },
75 { "XX", "234", "2" },
76 { "XX", "3456", "3" },
77 { "XX", "23456", "2" },
78 { "XX", "+1", "+1" },
79 { "XX", "-12", "-12" },
80 { "XX", "+123", "+123" },
81 { "XX", "-12:34", "-12" },
82 { "XX", "+12:34", "+12" },
83 { "XX", "-2423", "-2" },
84 { "XX", "+2423", "+2" },
85 { "XX", "-1260", "-126" },
86 { "XX", "+1260", "+126" },
87
88 { "XXX", "9", "9" },
89 { "XXX", "23", "2" },
90 { "XXX", "234", "2" },
91 { "XXX", "3456", "3" },
92 { "XXX", "23456", "2" },
93 { "XXX", "2:34", "2" },
94 { "XXX", "12:4", "1" },
95 { "XXX", "12:34", "1" },
96 { "XXX", "-1", "-1" },
97 { "XXX", "+1", "+1" },
98 { "XXX", "-12", "-12" },
99 { "XXX", "+12", "+12" },
100 { "XXX", "-123", "-12" },
101 { "XXX", "+123", "+12" },
102 { "XXX", "-1234", "-12" },
103 { "XXX", "+1234", "+12" },
104 { "XXX", "+24:23", "+2" },
105 { "XXX", "+12:60", "+12:6" },
106 { "XXX", "+1:23", "+1" },
107 { "XXX", "+12:3", "+12:3" },
108 };
109
110 static String[] badFormats = {
111 "XXXX", "XXXXX", "XXXXXX",
112 };
113
114 public static void main(String[] args) throws Exception {
115 TimeZone tz = TimeZone.getDefault();
116 Locale loc = Locale.getDefault();
117 Locale.setDefault(Locale.US);
118
119 try {
120 for (int i = 0; i < formatData.length; i++) {
121 TimeZone.setDefault(TimeZone.getTimeZone(formatData[i][0]));
122 formatTest(isoZoneFormats[i % isoZoneFormats.length],
123 formatData[i][1]);
124 }
125
126 for (String zone : zones) {
127 TimeZone.setDefault(TimeZone.getTimeZone(zone));
128 for (String fmt : isoZoneFormats) {
129 roundtripTest(fmt);
130 SimpleDateFormat f = new SimpleDateFormat(fmt);
131 }
132
133 }
134
135 for (String[] d : badData) {
136 badDataParsing(d[0], d[1], d[2].length());
137 }
138
139 for (String fmt : badFormats) {
140 badFormat(fmt);
141 }
142 } finally {
143 TimeZone.setDefault(tz);
144 Locale.setDefault(loc);
145 }
146
147 }
148
149 static void formatTest(String fmt, String expected) throws Exception {
150 SimpleDateFormat sdf = new SimpleDateFormat(fmt);
151 String s = sdf.format(TIMESTAMP);
152 if (!expected.equals(s)) {
153 throw new RuntimeException("formatTest: got " + s
154 + ", expected " + expected);
155 }
156
157 Date d = sdf.parse(s);
158 if (d.getTime() != TIMESTAMP.getTime()) {
159 throw new RuntimeException("formatTest: parse(" + s
160 + "), got " + d.getTime()
161 + ", expected " + TIMESTAMP.getTime());
162 }
163
164 ParsePosition pos = new ParsePosition(0);
165 d = sdf.parse(s + "123", pos);
166 if (d.getTime() != TIMESTAMP.getTime()) {
167 throw new RuntimeException("formatTest: parse(" + s
168 + "), got " + d.getTime()
169 + ", expected " + TIMESTAMP.getTime());
170 }
171 if (pos.getIndex() != s.length()) {
172 throw new RuntimeException("formatTest: wrong resulting parse position: "
173 + pos.getIndex() + ", expected " + s.length());
174 }
175 }
176
177 static void roundtripTest(String fmt) throws Exception {
178 SimpleDateFormat sdf = new SimpleDateFormat(fmt);
179 Date date = new Date();
180
181 int fractionalHour = sdf.getTimeZone().getOffset(date.getTime());
182 fractionalHour %= 3600000;
183
184 String s = sdf.format(date);
185 Date pd = sdf.parse(s);
186 long diffsInMillis = pd.getTime() - date.getTime();
187 if (diffsInMillis != 0) {
188 if (diffsInMillis != fractionalHour) {
189 throw new RuntimeException("fmt= " + fmt
190 + ", diff="+diffsInMillis
191 + ", fraction=" + fractionalHour);
192 }
193 }
194 }
195
196
197 static void badDataParsing(String fmt, String text, int expectedErrorIndex) {
198 SimpleDateFormat sdf = new SimpleDateFormat(fmt);
199 try {
200 sdf.parse(text);
201 throw new RuntimeException("didn't throw an exception: fmt=" + fmt
202 + ", text=" + text);
203 } catch (ParseException e) {
204
205 }
206
207 ParsePosition pos = new ParsePosition(0);
208 Date d = sdf.parse(text, pos);
209 int errorIndex = pos.getErrorIndex();
210 if (d != null || errorIndex != expectedErrorIndex) {
211 throw new RuntimeException("Bad error index=" + errorIndex
212 + ", expected=" + expectedErrorIndex
213 + ", fmt=" + fmt + ", text=" + text);
214 }
215 }
216
217 static void badFormat(String fmt) {
218 try {
219 SimpleDateFormat sdf = new SimpleDateFormat(fmt);
220 throw new RuntimeException("Constructor didn't throw an exception: fmt=" + fmt);
221 } catch (IllegalArgumentException e) {
222
223 }
224 try {
225 SimpleDateFormat sdf = new SimpleDateFormat();
226 sdf.applyPattern(fmt);
227 throw new RuntimeException("applyPattern didn't throw an exception: fmt=" + fmt);
228 } catch (IllegalArgumentException e) {
229
230 }
231 }
232 }